/*
 *  ETA/OS - Python header
 *  Copyright (C) 2017   Michel Megens <dev@bietje.net>
 *  Copyright (C) 2017   Dean Hall
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Lesser General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public License
 *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#ifndef __CODEOBJ_H__
#define __CODEOBJ_H__

/**
 * \file
 * \brief CodeObj Type
 *
 * CodeObj type header.
 */

/** Code image field offset consts */
#define CI_TYPE_FIELD       0
#define CI_SIZE_FIELD       1
#define CI_ARGCOUNT_FIELD   3
#define CI_FLAGS_FIELD      4
#define CI_STACKSIZE_FIELD  5
#define CI_NLOCALS_FIELD    6

#ifdef HAVE_CLOSURES
#define CI_FREEVARS_FIELD  7
#ifdef HAVE_DEBUG_INFO
#define CI_FIRST_LINE_NO  8
#define CI_NAMES_FIELD    10
#else
#define CI_NAMES_FIELD    8
#endif				/* HAVE_DEBUG_INFO */
#else
#ifdef HAVE_DEBUG_INFO
#define CI_FIRST_LINE_NO  7
#define CI_NAMES_FIELD    9
#else
#define CI_NAMES_FIELD    7
#endif				/* HAVE_DEBUG_INFO */
#endif				/* HAVE_CLOSURES */

/** Native code image size */
#define NATIVE_IMAGE_SIZE   4

/* Masks for co_flags (from Python's code.h) */
#define CO_OPTIMIZED 0x01
#define CO_NEWLOCALS 0x02
#define CO_VARARGS 0x04
#define CO_VARKEYWORDS 0x08
#define CO_NESTED 0x10
#define CO_GENERATOR 0x20
#define CO_NOFREE 0x40

/**
 * Code Object
 *
 * An extended object that holds only the most frequently used parts
 * of the static code image.  Other parts can be obtained by
 * inspecting the code image itself.
 */
typedef struct PmCo_s {
    /** Object descriptor */
	PmObjDesc_t od;
    /** Address in progmem of the code image, or of code img obj in heap */
	uint8_t const *co_codeimgaddr;
    /** Address in RAM of names tuple */
	pPmTuple_t co_names;
    /** Address in RAM of constants tuple */
	pPmTuple_t co_consts;
    /** Address in memspace of bytecode (or native function) */
	uint8_t const *co_codeaddr;

#ifdef HAVE_DEBUG_INFO
    /** Address in memspace of the line number table */
	uint8_t const *co_lnotab;
    /** Address in memspace of the filename */
	uint8_t const *co_filename;
    /** Line number of first source line of lnotab */
	uint16_t co_firstlineno;
#endif				/* HAVE_DEBUG_INFO */

#ifdef HAVE_CLOSURES
    /** Address in RAM of cellvars tuple */
	pPmTuple_t co_cellvars;
    /** Number of freevars */
	uint8_t co_nfreevars;
#endif				/* HAVE_CLOSURES */

    /** Memory space selector */
	PmMemSpace_t co_memspace:8;
    /** Number of positional arguments the function expects */
	uint8_t co_argcount;
    /** Compiler flags */
	uint8_t co_flags;
    /** Stack size */
	uint8_t co_stacksize;
    /** Number of local variables */
	uint8_t co_nlocals;
} PmCo_t, *pPmCo_t;

/**
 * Native Code Object
 *
 * An extended object that holds only the most frequently used parts
 * of the static native image.  Other parts can be obtained by
 * inspecting the native image itself.
 */
typedef struct PmNo_s {
    /** object descriptor */
	PmObjDesc_t od;
    /** expected num args to the func */
	int8_t no_argcount;
    /** index into native function table */
	int16_t no_funcindx;
} PmNo_t, *pPmNo_t;

/**
 * Creates a CodeObj by loading info from a code image in memory.
 *
 * An image is a static representation of a Python object.
 * The process of converting an object to and from an image
 * is also called marshalling.
 * In PyMite, code images are the equivalent of .pyc files.
 * Code images can only contain a select subset of object types
 * (None, Int, Float, String, Slice?, Tuple, and CodeImg).
 * All other types (Lists, Dicts, CodeObjs, Modules, Classes,
 * Functions, ClassInstances) are built at runtime.
 *
 * All multibyte values are in Little Endian order
 * (least significant byte comes first in the byte stream).
 *
 * memspace and *paddr determine the start of the code image.
 * Load the code object with values from the code image,
 * including the names and consts tuples.
 * Leave contents of paddr pointing one byte past end of
 * code img.
 *
 * The code image has the following structure:
 *      -type:      8b - OBJ_TYPE_CIM
 *      -size:      16b - number of bytes
 *                  the code image occupies.
 *      -argcount:  8b - number of arguments to this code obj.
 *      -stacksz:   8b - the maximum arg-stack size needed.
 *      -nlocals:   8b - number of local vars in the code obj.
 *      -names:     Tuple - tuple of string objs.
 *      -consts:    Tuple - tuple of objs.
 *      -code:      8b[] - bytecode array.
 *
 * @param   memspace memory space containing image
 * @param   paddr ptr to ptr to code img in memspace
 *          return by reference: paddr points one byte
 *          past end of code img
 * @param   r_pco Return arg.  New code object with fields
 *          filled in.
 * @return  Return status
 */
PmReturn_t
co_loadFromImg(PmMemSpace_t memspace, uint8_t const **paddr, pPmObj_t * r_pco);

/**
 * Recursively sets image address of the CO and all its nested COs
 * in its constant pool.  This is done so that an image that was
 * received during an interactive session will persist as long as any
 * of its COs/funcs/objects is still alive.
 *
 * @param   pco Pointer to root code object whose images are set
 * @param   pimg Pointer to very top of code image (PmodeImgObj)
 */
void co_rSetCodeImgAddr(pPmCo_t pco, uint8_t const *pimg);

/**
 * Creates a Native code object by loading a native image.
 *
 * An image is a static representation of a Python object.
 * A native image is much smaller than a regular image
 * because only two items of data are needed after the type:
 * the number of args the func expects and the index into
 * the native function table.
 * A reference to the image is not needed since it is
 * just as efficient to store the info in RAM as it is to
 * store a pointer and memspace value.
 *
 * memspace and *paddr determine the start of the native image.
 * Loads the argcount and the func index from the native object.
 * Leaves contents of paddr pointing one byte past end of
 * code img.
 *
 * The native image has the following structure:
 *      -type:      8b - OBJ_TYPE_CIM
 *      -argcount:  8b - number of arguments to this code obj.
 *      -code:      16b - index into native function table.
 *
 * @param   memspace memory space containing image
 * @param   paddr ptr to ptr to code img in memspace (return)
 * @param   r_pno Return by reference, new code object
 * @return  Return status
 */
PmReturn_t no_loadFromImg(PmMemSpace_t memspace,
			  uint8_t const **paddr, pPmObj_t * r_pno);

#endif				/* __CODEOBJ_H__ */
